/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package modelo.conexion;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import modelo.DiaTablespace;
import modelo.Indice;
import modelo.Tabla;
import modelo.Tablespace;
import modelo.Usuario;
import modelo.regresion.RegresionLineal;

/**
 *
 * @author Andrés
 */
public class RecolectorDatos {

    private Connection conexion;
    private CallableStatement callableStatement;
    private Statement statement;
    private ResultSet rs;
    private static final String procedimiento_INFOTS = "{call INFOTS(?)}";
    private static final String procedimiento_INFOFTS = "{call INFOFSP(?)}";
    private static final String procedimiento_Desfragmenta = "{call DESFRAGMENTA(?,?)}";
    private static final String procedimiento_Indices = "{call indices(?,?)}";
    private static final String procedimiento_Tablespaces = "{call TABLESPACES(?)}";
    private static final String procedimiento_Usuarios = "{call TABLA(?)}";
    private static final String procedimiento_CREAUSUARIO = "{call CREAUSUARIO(?,?,?,?,?)}";
    private static final String procedimiento_ROLESUSUARIO = "{call ROLESUSUARIO(?,?)}";
    private static final String procedimiento_PRIVILEGIOS = "{call PRIVILEGIOS(?,?)}";
    private static final String procedimiento_OBJETOS = "{call OBJETOS(?,?)}";
    private static final String procedimiento_QUOTAS = "{call QUOTAS(?,?)}";
    private static final String procedimiento_PRIVSISTEMA = "{call PRIVSISTEMA(?)}";
    private static final String procedimiento_ROLESSISTEMA = "{call ROLESSISTEMA(?)}";
    private static final String procedimiento_CREAROL = "{call CREAROL(?,?)}";
    private static final String procedimiento_ASIGNAPRIV = "{call ASIGNAPRIV(?,?)}";
    private static final String procedimiento_ASIGNAROL = "{call ASIGNAROL(?,?)}";
    private static final String procedimiento_CAMBIACLAVE = "{call CAMBIACLAVE(?,?)}";
    private static final String procedimiento_BLOQUEAUSUARIO = "{call BLOQUEAUSUARIO(?)}";
    private static final String procedimiento_ACTIVAUSUARIO = "{call ACTIVAUSUARIO(?)}";
    private static final String procedimiento_CONSULTA_PRIVUSUARIO = "{call CONSULTA_PRIVUSUARIO(?,?)}";
    private static final String procedimiento_INICIORESPALDO = "{call INICIARESPALDO(?)}";
    private static final String procedimiento_FILE_NAMES_CURSOR = "{call FILE_NAMES_CURSOR(?,?)}";
    private static final String procedimiento_FINRESPALDO = "{call FINRESPALDO(?)}";
    private static final String procedimiento_ULTIMAS_CONSULTAS = "{call ULTIMAS_CONSULTAS(?)}";
    private SimpleDateFormat sdf;

    public RecolectorDatos(Connection conexion) throws SQLException {
        this.conexion = conexion;
        callableStatement = conexion.prepareCall(procedimiento_INFOTS);
        this.sdf = new SimpleDateFormat("dd-MM-yyyy");
    }

    public RecolectorDatos() {
        this.sdf = new SimpleDateFormat("dd-MM-yyyy");
    }

    public Connection getConexion() {
        return conexion;
    }

    public void setConexion(Connection conexion) throws SQLException {
        this.conexion = conexion;
        this.callableStatement = conexion.prepareCall(procedimiento_INFOTS);
    }

    public String getFecha() {
        Date d = Calendar.getInstance().getTime();
        String currentData = sdf.format(d);
        return currentData;
    }

    public void recolectarInfoTablespaces(List<Tablespace> tablespaces, RegresionLineal lineal) throws SQLException {
        String fecha = getFecha();
        callableStatement.registerOutParameter(1, oracle.jdbc.driver.OracleTypes.CURSOR);
        callableStatement.executeUpdate();
        ResultSet rs;
        rs = (ResultSet) callableStatement.getObject(1);
        int index;
        while (rs.next()) {
            String nombreTablespace = rs.getString(1);
            String nombreTabla = rs.getString(2);
            String filas = rs.getString(3);
            String tamano = rs.getString(4);
            //String nuevos = rs.getString(5);
            int i_filas;
            int i_nuevos;
            if (filas == null) {
                i_filas = 0;
                i_nuevos = 0;
            } else {
                i_filas = Integer.parseInt(filas);
                // i_nuevos= Integer.parseInt(nuevos);
            }
            float f_tamano = Float.parseFloat(tamano);
            index = indiceTablespace(nombreTablespace, tablespaces);
            if (index == -1) {
                Tablespace t = new Tablespace(nombreTablespace);
                t.agregarDia(new DiaTablespace(fecha));
                tablespaces.add(t);
                Tabla tabla = new Tabla(nombreTabla, i_filas, f_tamano, 0);
                index = indiceTablespace(nombreTablespace, tablespaces);
                tablespaces.get(index).getDiaTablespace(fecha).agregarTabla(tabla);
                lineal.agrega(nombreTablespace, nombreTabla, f_tamano, i_filas);
            } else {
                if (!tablespaces.get(index).diaExistente(fecha)) {
                    tablespaces.get(index).agregarDia(new DiaTablespace(fecha));
                }
                if (!tablespaces.get(index).getDiaTablespace(fecha).tablaExistente(nombreTabla)) {
                    Tabla tabla = new Tabla(nombreTabla, i_filas, f_tamano, 0);
                    tablespaces.get(index).getDiaTablespace(fecha).agregarTabla(tabla);
                    lineal.agrega(nombreTablespace, nombreTabla, f_tamano, i_filas);
                }
            }
        }
    }

    public void recolectarInfoFreeTablespaces(List<Tablespace> tablespaces, RegresionLineal lineal) throws SQLException {
        this.callableStatement = conexion.prepareCall(procedimiento_INFOFTS);
        callableStatement.registerOutParameter(1, oracle.jdbc.driver.OracleTypes.CURSOR);
        callableStatement.executeUpdate();
        ResultSet rs;
        rs = (ResultSet) callableStatement.getObject(1);
        boolean existe = false;
        while (rs.next()) {
            String nombre = rs.getString(1);
            String usado = rs.getString(2);
            String libre = rs.getString(3);
            String prct_libre = rs.getString(4);
            existe = false;
            for (Tablespace tb : tablespaces) {
                int dia = tb.cantidadDias();
                if (tb.getNombre().equals(nombre)) {
                    existe = true;
                    tb.agregarInfoDiaTablespace(getFecha(), Float.parseFloat(prct_libre),
                            Integer.parseInt(usado), Integer.parseInt(libre));
                    lineal.setEspacios(tb.getNombre(), Float.parseFloat(libre), Float.parseFloat(usado));
                }
            }
            if (!existe) {
                Tablespace nuevo = new Tablespace(nombre);
                tablespaces.add(nuevo);
                nuevo.agregarInfoDiaTablespace(getFecha(), Float.parseFloat(prct_libre),
                        Integer.parseInt(usado), Integer.parseInt(libre));
            }
        }
    }

    public int indiceTablespace(String nombre, List<Tablespace> tablespaces) {
        int i = 0;
        for (Tablespace tablespace : tablespaces) {
            if (tablespace.getNombre().equals(nombre)) {
                return i;
            }
            i++;
        }
        return -1;
    }

    public void desfragmentar(ArrayList<Indice> indices) throws SQLException {
        for (Indice indi : indices) {
            desfragmentar(indi.getNombre(), indi.getOwner());
        }
    }

    public void desfragmentar(String indice, String owner) throws SQLException {
        CallableStatement cState;
        cState = conexion.prepareCall(procedimiento_Desfragmenta);
        cState.setString(1, indice);
        cState.setString(2, owner);
        cState.executeUpdate();
    }

    public void respaldar(String tablespace) throws SQLException {
        CallableStatement cState;
        cState = conexion.prepareCall(procedimiento_INICIORESPALDO);
        cState.setString(1, tablespace);
        cState.executeUpdate();

        //         
        CallableStatement cState2;
        cState2 = conexion.prepareCall(procedimiento_FILE_NAMES_CURSOR);
        cState2.registerOutParameter(1, oracle.jdbc.driver.OracleTypes.CURSOR);
        cState2.setString(2, tablespace);
        cState2.executeUpdate();
        ResultSet rs2;
        rs2 = (ResultSet) cState2.getObject(1);
        File original;// = new File("C:\\oraclexe\\app\\oracle\\oradata\\XE\\USERS.DBF");
        if (!new File("C:\\Respaldos").exists()) {
            new File("C:\\Respaldos").mkdir();
        }
        File respaldo = new File("C:\\Respaldos\\" + tablespace + ".DBF");
        while (rs2.next()) {
            String origen = rs2.getString(1);
            original = new File(origen);
            try {
                copyFile(original, respaldo);
            } catch (IOException ex) {
                Logger.getLogger(RecolectorDatos.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
        //       
        CallableStatement cState1;
        cState1 = conexion.prepareCall(procedimiento_FINRESPALDO);
        cState1.setString(1, tablespace);
        cState1.executeUpdate();

    }
    
    public List<String> ultimasConsultas()throws SQLException  {
    
        List<String> listConsulta =  new ArrayList<>();
        
        CallableStatement cState;
        cState = conexion.prepareCall(procedimiento_ULTIMAS_CONSULTAS);
        cState.registerOutParameter(1, oracle.jdbc.driver.OracleTypes.CURSOR);
        cState.executeUpdate();
        ResultSet rs;
        rs = (ResultSet) cState.getObject(1);
        while (rs.next()) {
            String sentenciaSQL = rs.getString(1);
//            String Estado = rs.getString(2);
//            String MB_Tamaño = rs.getString(3);
//            String MB_Usados = rs.getString(4);
//            String MB_Libres = rs.getString(5);
//            String Fichero_datos = rs.getString(7);  
            
            listConsulta.add(sentenciaSQL);
            
            //listConsulta.add(new Consulta(Tablespace, Estado, MB_Tamaño, MB_Usados, MB_Libres, Fichero_datos));            
        }              
        for(String c : listConsulta){
           System.out.println(c.toString());         
        }
        return listConsulta;
    }

    public static void copyFile(File from, File to) throws IOException {
        Files.copy(from.toPath(), to.toPath(), REPLACE_EXISTING);
    }

    public void obtenerInfoIndices(ArrayList<Indice> indices) throws SQLException {
        indices.clear();
        CallableStatement cStatemen;
        double a = -1;
        cStatemen = conexion.prepareCall(procedimiento_Indices);
        cStatemen.registerOutParameter(1, oracle.jdbc.driver.OracleTypes.CURSOR);
        cStatemen.setDouble(2, a);
        cStatemen.executeUpdate();
        ResultSet rs = (ResultSet) cStatemen.getObject(1);
        while (rs.next()) {
            indices.add(new Indice(rs.getString(1), rs.getString(3), Float.valueOf(rs.getString(2))));
        }
    }

    public void obtenerTablespaces(List<String> tablespaces) throws SQLException {
        callableStatement = conexion.prepareCall(procedimiento_Tablespaces);
        callableStatement.registerOutParameter(1, oracle.jdbc.driver.OracleTypes.CURSOR);
        callableStatement.executeUpdate();
        rs = (ResultSet) callableStatement.getObject(1);
        while (rs.next()) {
            tablespaces.add(rs.getString(1));
        }
    }

    public void obtenerPrivilegios(List<String> privilegios) throws SQLException {
        callableStatement = conexion.prepareCall(procedimiento_PRIVSISTEMA);
        callableStatement.registerOutParameter(1, oracle.jdbc.driver.OracleTypes.CURSOR);
        callableStatement.executeUpdate();
        rs = (ResultSet) callableStatement.getObject(1);
        while (rs.next()) {
            privilegios.add(rs.getString(1));
        }
    }

    public void obtenerRoles(List<String> roles) throws SQLException {
        callableStatement = conexion.prepareCall(procedimiento_ROLESSISTEMA);
        callableStatement.registerOutParameter(1, oracle.jdbc.driver.OracleTypes.CURSOR);
        callableStatement.executeUpdate();
        rs = (ResultSet) callableStatement.getObject(1);
        while (rs.next()) {
            roles.add(rs.getString(1));
        }
    }
    
    public String consultarUsuarioDesActivo(String usuario) throws SQLException{
        callableStatement = conexion.prepareCall(procedimiento_CONSULTA_PRIVUSUARIO);
        callableStatement.registerOutParameter(1, oracle.jdbc.driver.OracleTypes.CURSOR);
        callableStatement.setString(2, usuario);
        callableStatement.executeUpdate();
        rs = (ResultSet) callableStatement.getObject(1);
        usuario = "";
        while (rs.next()) {
            usuario = rs.getString(1);
        }
        return usuario;
    }

    public void obtenerUsuarios(List<Usuario> usuarios) throws SQLException {
        callableStatement = conexion.prepareCall(procedimiento_Usuarios);
        callableStatement.registerOutParameter(1, oracle.jdbc.driver.OracleTypes.CURSOR);
        callableStatement.executeUpdate();
        rs = (ResultSet) callableStatement.getObject(1);
        while (rs.next()) {
            Usuario usuario = new Usuario();
            usuario.setUser(rs.getString(1));
            usuario.setDefaultTablespace(rs.getString(2));
            usuario.setTemporaryTablespace(rs.getString(3));
            usuarios.add(usuario);
            System.out.println("Usuario: " + usuario);
        }
    }

    public void obtenerInformacionDeUsuario(List<String> informacionUsuarios, String opcion, String usuario) throws SQLException {
        System.out.println("Consultando: " + opcion + "...");
        switch (opcion) {
            case "Roles asociados":
                callableStatement = conexion.prepareCall(procedimiento_ROLESUSUARIO);
                this.obtenerInformacionDeUsuario(callableStatement, informacionUsuarios, usuario);
                break;

            case "Privilegios asociados":
                callableStatement = conexion.prepareCall(procedimiento_PRIVILEGIOS);
                this.obtenerInformacionDeUsuario(callableStatement, informacionUsuarios, usuario);
                break;

            case "Objetos asociados":
                callableStatement = conexion.prepareCall(procedimiento_OBJETOS);
                this.obtenerInformacionDeUsuario(callableStatement, informacionUsuarios, usuario);
                break;

            case "Cuotas por tablespace":
                callableStatement = conexion.prepareCall(procedimiento_QUOTAS);
                this.obtenerInformacionDeUsuario(callableStatement, informacionUsuarios, usuario);
                for (int i = 0; i < informacionUsuarios.size(); i++) {
                    if (informacionUsuarios.get(i).equals("-1")) {
                        informacionUsuarios.set(i, "UNLIMITED");
                    } else {
                        int cuota = Integer.valueOf(informacionUsuarios.get(i));
                        cuota = cuota / 1024 / 1024;
                        informacionUsuarios.set(i, String.valueOf(cuota) + " MB");
                    }
                }
                break;
        }
    }

    public void obtenerInformacionDeUsuario(CallableStatement callableStatement, List<String> informacionUsuarios, String usuario) throws SQLException {
        callableStatement.registerOutParameter(1, oracle.jdbc.driver.OracleTypes.CURSOR);
        callableStatement.setString(2, usuario);
        callableStatement.executeUpdate();
        rs = (ResultSet) callableStatement.getObject(1);
        while (rs.next()) {
            informacionUsuarios.add(rs.getString(1));
        }
    }

    public void administrarUsuarios(String accion, List<String> requisitos) throws SQLException {
        System.out.println("Ejecutando la sentencia: " + accion + ", requisitos: " + requisitos);
        int i = 0;
        switch (accion) {
            case "Crear usuario":
                callableStatement = conexion.prepareCall(procedimiento_CREAUSUARIO);
                for (String requisito : requisitos) {
                    callableStatement.setString(++i, requisito);
                }
                callableStatement.executeUpdate();
                break;

            case "Crear role":
                callableStatement = conexion.prepareCall(procedimiento_CREAROL);
                callableStatement.setString(1, requisitos.get(0));
                callableStatement.setString(2, requisitos.get(1));
                callableStatement.executeUpdate();

                callableStatement = conexion.prepareCall(procedimiento_ASIGNAPRIV);
                callableStatement.setString(1, requisitos.get(0));
                callableStatement.setString(2, requisitos.get(2));
                callableStatement.executeUpdate();
                break;

            case "Asignar rol":
                callableStatement = conexion.prepareCall(procedimiento_ASIGNAROL);
                callableStatement.setString(1, requisitos.get(0));
                callableStatement.setString(2, requisitos.get(1));
                callableStatement.executeUpdate();
                break;
                
            case "Activar usuario":
                callableStatement = conexion.prepareCall(procedimiento_ACTIVAUSUARIO);
                callableStatement.setString(1, requisitos.get(0));
                callableStatement.executeUpdate();
                break;    
                
            case "Desactivar usuario":
                callableStatement = conexion.prepareCall(procedimiento_BLOQUEAUSUARIO);
                callableStatement.setString(1, requisitos.get(0));
                callableStatement.executeUpdate();
                break;

            case "Guardar contraseña":
                callableStatement = conexion.prepareCall(procedimiento_CAMBIACLAVE);
                callableStatement.setString(1, requisitos.get(0));
                callableStatement.setString(2, requisitos.get(1));
                callableStatement.executeUpdate();
                break;
        }
    }
}
